#include "game_platform.h"
#include "game_file_format.h"

struct bitmap_asset {
    const char *FileName;
    real32 AlignPercentage[2];
};

enum asset_type {
    AssetType_Sound,
    AssetType_Bitmap,
    AssetType_Font,
    AssetType_FontGlyph,
};

struct loaded_font;
struct asset_source_font {
    loaded_font *Font;
};
struct asset_source_font_glyph {
    loaded_font *Font;
    uint32 CodePoint;
};
struct asset_source_sound {
    const char *FileName;
    uint32 FirstSampleIndex;
};

struct asset_source_bitmap {
    const char *FileName;
};

struct asset_source {
    asset_type Type;
    union {
        asset_source_bitmap Bitmap;
        asset_source_sound Sound;
        asset_source_font Font;
        asset_source_font_glyph Glyph;
    };
};

#define VERY_LARGE_NUMBER 4096
struct game_assets {
    uint32 TagCount;
    hha_tag Tags[VERY_LARGE_NUMBER];

    uint32 AssetCount;
    asset_source AssetSource[VERY_LARGE_NUMBER];
    hha_asset Assets[VERY_LARGE_NUMBER];

    uint32 AssetTypeCount;
    hha_asset_type AssetTypes[VERY_LARGE_NUMBER];

    hha_asset_type *DEBUGAssetType;
    uint32 AssetIndex;
};

internal void BeginAssetType(game_assets *Assets, assets_type_id TypeID) {
    Assert(Assets->DEBUGAssetType == 0);
    Assets->DEBUGAssetType = Assets->AssetTypes + TypeID;
    Assets->DEBUGAssetType->TypeID = TypeID;
    Assets->DEBUGAssetType->FirstAssetIndex = Assets->AssetCount;
    Assets->DEBUGAssetType->OnePastLastAssetIndex = Assets->DEBUGAssetType->FirstAssetIndex;
}

struct added_asset {
    uint32 ID;
    hha_asset *HHA;
    asset_source *Source;
};
internal added_asset AddAsset(game_assets *Assets) {
    Assert(Assets->DEBUGAssetType);
    Assert(Assets->DEBUGAssetType->OnePastLastAssetIndex < ArrayCount(Assets->Assets));
    uint32 Index = {Assets->DEBUGAssetType->OnePastLastAssetIndex++};
    hha_asset *HHA = Assets->Assets + Index;
    HHA->FirstTagIndex = Assets->TagCount;
    HHA->OnePastLastTagIndex = HHA->FirstTagIndex;
    Assets->AssetIndex = Index;
    added_asset Result;
    Result.ID = Index;
    Result.HHA = HHA;
    Result.Source = Assets->AssetSource + Index;
    return Result;
}

internal bitmap_id AddBitmapAsset(game_assets *Assets, const char *FileName,
                                  real32 AlignPercentageX = 0.5, real32 AlignPercentageY = 0.5) {
    added_asset Asset = AddAsset(Assets);
    Asset.HHA->Bitmap.AlignPercentage[0] = AlignPercentageX;
    Asset.HHA->Bitmap.AlignPercentage[1] = AlignPercentageY;

    Asset.Source->Type = AssetType_Bitmap;
    Asset.Source->Bitmap.FileName = FileName;
    Assets->AssetIndex = Asset.ID;
    bitmap_id Result{Asset.ID};
    return Result;
}

#include <windows.h>
struct loaded_font {
    uint32 CodePointCount;
    real32 AscenderHeight;
    real32 DescenderHeight;
    real32 ExternalLeading;
    TEXTMETRIC TextMetric;
    HFONT Win32Handle;

    hha_font_glyph *Glyphs;
    uint32 MinCodePoint;
    uint32 MaxCodePoint;
    uint32 MaxGlyphCount;
    uint32 GlyphCount;
    real32 *HorizontalAdvance;

    uint32 OnePastHighestCodePoint;
    uint32 *GlyphIndexFromCodePoint;
};

internal font_id AddFontAsset(game_assets *Assets, loaded_font *Font) {
    added_asset Asset = AddAsset(Assets);
    Asset.HHA->Font.GlyphCount = Font->GlyphCount;
    Asset.HHA->Font.OnePastHeighestCodePoint = Font->OnePastHighestCodePoint;

    Asset.HHA->Font.AscenderHeight = (real32)Font->TextMetric.tmAscent;
    Asset.HHA->Font.DescenderHeight = (real32)Font->TextMetric.tmDescent;
    Asset.HHA->Font.ExternalLeading = real32(Font->TextMetric.tmExternalLeading);

    Asset.Source->Type = AssetType_Font;
    Asset.Source->Font.Font = Font;
    Assets->AssetIndex = Asset.ID;
    font_id Result{Asset.ID};
    return Result;
}

internal bitmap_id AddCharacterAsset(game_assets *Assets, loaded_font *Font, uint32 CodePoint) {
    added_asset Asset = AddAsset(Assets);
    Asset.HHA->Bitmap.AlignPercentage[0] = 0.0f;
    Asset.HHA->Bitmap.AlignPercentage[1] = 0.0f;

    Asset.Source->Type = AssetType_FontGlyph;
    Asset.Source->Glyph.Font = Font;
    Asset.Source->Glyph.CodePoint = CodePoint;

    bitmap_id Result = {Asset.ID};

    Assert(Font->GlyphCount < Font->MaxGlyphCount);
    uint32 GlyphIndex = Font->GlyphCount++;
    hha_font_glyph *Glyph = Font->Glyphs + GlyphIndex;
    Glyph->UnicodeCodePoint = CodePoint;
    Glyph->BitmapID = Result;

    Font->GlyphIndexFromCodePoint[CodePoint] = GlyphIndex;
    if (Font->OnePastHighestCodePoint <= CodePoint) {
        Font->OnePastHighestCodePoint = CodePoint + 1;
    }
    Assets->AssetIndex = Asset.ID;
    return Result;
}

internal sound_id AddSoundAsset(game_assets *Assets, const char *FileName,
                                uint32 FirstSampleIndex = 0, uint32 SampleCount = 0) {
    added_asset Asset = AddAsset(Assets);
    Asset.HHA->Sound.SampleCount = SampleCount;
    Asset.HHA->Sound.Chain = HHASoundChain_None;
    Asset.Source->Sound.FileName = FileName;
    Asset.Source->Type = AssetType_Sound;
    Asset.Source->Sound.FirstSampleIndex = FirstSampleIndex;

    sound_id Result = {Asset.ID};
    return Result;
}

internal void AddTag(game_assets *Assets, asset_tag_id ID, real32 Value) {
    Assert(Assets->AssetIndex);
    hha_asset *HHA = Assets->Assets + Assets->AssetIndex;
    ++HHA->OnePastLastTagIndex;
    hha_tag *Tag = Assets->Tags + Assets->TagCount++;
    Tag->ID = ID;
    Tag->Value = Value;
}

internal void EndAssetType(game_assets *Assets) {
    Assert(Assets->DEBUGAssetType);
    Assets->AssetCount = Assets->DEBUGAssetType->OnePastLastAssetIndex;
    Assets->DEBUGAssetType = 0;
    Assets->AssetIndex = 0;
}
